/**
 * 函数的柯里化 多个参数的传入 把他转化成N个函数 可以暂存变量
 * 一般函数的柯里化要求参数一个一个传 =》 偏函数
 */

//
// isType(null)

function isString(typing) {
    return function (val) {
        return Object.prototype.toString.call(val) === `[object ${typing}]`;
    }
}

let myIsString = isString('String');

const res = myIsString('123');

console.log(res);

// 实现通用的柯里化函数： 高阶函数

// 记录，每次调用时传入的参数，并且和函数的参数个数进行判断，不满足总个数就返回新函数，满足则执行原来的函数

// function curring(fn) {
//     let argsLength = 0;
//     let argsArray = [];
//     let temp = function (...args) {
//         console.log(args);
//         argsLength += args.length;
//         if (args.length) {
//             argsArray =  argsArray.concat(args)
//         }
//         if (argsLength === 4) {
//             return fn(...argsArray);
//         } else {
//             return temp;
//         }
//     }
//     return temp;
// }

function curring(fn) {
    const inner = (args = []) => {
        // 函数的length方法方法定义时接受的参数个数
        return args.length >= fn.length ? fn(...args) : (...userArgs) => inner([...args, ...userArgs])
    }

    return inner();
}

function sum(a, b, c, d) {
    console.log(a, b, c, d)
    return a + b + c + d;
}

let sum1 = curring(sum);
let sum2 = sum1(1);
let sum3 = sum2(2, 3);
let result = sum3(4);
console.log('sum length is:', sum.length)
console.log(result)

// 通用类型判断

/**
 * 柯里化： 让函数变得更具体
 * 反柯里化： 让函数变得更广泛
 */
function isType(typing, val) {
    console.log(Object.prototype.toString.call(val));
    return Object.prototype.toString.call(val) === `[object ${typing}]`;
}

let isString1 = curring(isType);
console.log(isString1('String')('ad'))
console.log(isString1('Number')(123))

console.log(isType('Object', {a: 1}))

const util = {};
['String', 'Number', 'Undefined', 'Null', 'Boolean', 'Object'].forEach((key) => {
    const curringFn = curring(isType);
    util[`is${key}`] = curringFn(key)
})

console.log(util)